package com.ihy.utils;

import com.arcsoft.face.*;
import com.arcsoft.face.enums.DetectMode;
import com.arcsoft.face.enums.DetectModel;
import com.arcsoft.face.enums.DetectOrient;
import com.arcsoft.face.enums.ErrorInfo;
import com.arcsoft.face.toolkit.ImageInfo;
import com.arcsoft.face.toolkit.ImageInfoEx;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import static com.arcsoft.face.toolkit.ImageFactory.getGrayData;
import static com.arcsoft.face.toolkit.ImageFactory.getRGBData;

/**
 * 虹软人脸识别工具类
 */
@Slf4j
public class FaceRecognitionUtil {
    public static FaceEngine faceEngine;
    public static int errorCode;
    public static FunctionConfiguration functionConfiguration;
    private static ImageInfo imageInfo;
    private static List<FaceInfo> faceInfoList;

    static {
        //从官网获取
        String appId = "2dqyeeX44jn9sfY4hdoEfk8bZe19Qm9ymkXLjj43JQ14";
        String sdkKey = "Fw1rNCkNttsBvJrG6LFuMsTnphVLXZfNCRXmGh5udr3L";
        faceEngine = new FaceEngine("F:\\Application\\project\\ihybm\\src\\main\\resources\\arcsoft\\dll\\win64\\");
        //激活引擎
        int errorCode = faceEngine.activeOnline(appId, sdkKey);
        if (errorCode != ErrorInfo.MOK.getValue() && errorCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) {
            log.info("引擎激活失败:{}", errorCode);
        }
        ActiveFileInfo activeFileInfo = new ActiveFileInfo();
        errorCode = faceEngine.getActiveFileInfo(activeFileInfo);
        if (errorCode != ErrorInfo.MOK.getValue() && errorCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) {
            log.info("获取激活文件信息失败:{}", errorCode);
        }
        //引擎配置
        EngineConfiguration engineConfiguration = new EngineConfiguration();
        //处理图像数据
        engineConfiguration.setDetectMode(DetectMode.ASF_DETECT_MODE_IMAGE);
        //全角度检测
        engineConfiguration.setDetectFaceOrientPriority(DetectOrient.ASF_OP_ALL_OUT);
        //最多能检测出的人脸数
        engineConfiguration.setDetectFaceMaxNum(10);
        //设置人脸相对于所在图片的长边的占比，在视频模式(ASF_DETECT_MODE_VIDEO)下有效值范围[2，32]，在图像模式(ASF_DETECT_MODE_IMAGE)下有效值范围[2，32]
        engineConfiguration.setDetectFaceScaleVal(16);
        //功能配置
        FunctionConfiguration functionConfiguration = new FunctionConfiguration();
        //设置是否支持年龄检测
        functionConfiguration.setSupportAge(true);
        //设置是否支持3D人脸检测
        functionConfiguration.setSupportFace3dAngle(true);
        //设置是否支持人脸检测
        functionConfiguration.setSupportFaceDetect(true);
        //设置是否支持人脸识别
        functionConfiguration.setSupportFaceRecognition(true);
        //设置是否支持性别检测
        functionConfiguration.setSupportGender(true);
        //设置是否支持RGB活体检测
        functionConfiguration.setSupportLiveness(true);
        //设置是否支持IR活体检测
        functionConfiguration.setSupportIRLiveness(true);
        //设置引擎功能配置
        engineConfiguration.setFunctionConfiguration(functionConfiguration);
        //初始化引擎
        errorCode = faceEngine.init(engineConfiguration);
        if (errorCode != ErrorInfo.MOK.getValue()) {
            log.info("初始化引擎失败:{}", errorCode);
        }
    }

    /**
     * 特征比较
     *
     * @param t1 图1
     * @param t2 图2
     * @param irt ir图
     * @return HashMap<String, Object>
     */
    public static HashMap<String, Object> compareFaceFeature(String t1, String t2,String irt) {
        HashMap<String, Object> map = new HashMap<>();
        //人脸检测
        imageInfo = getRGBData(new File(t1));
        faceInfoList = new ArrayList<>();
        errorCode = faceEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList);
        //特征提取
        FaceFeature faceFeature = new FaceFeature();
        errorCode = faceEngine.extractFaceFeature(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList.get(0), faceFeature);
        map.put("1特征值大小", faceFeature.getFeatureData().length);
        //人脸检测2
        ImageInfo imageInfo2 = getRGBData(new File(t2));
        List<FaceInfo> faceInfoList2 = new ArrayList<>();
        errorCode = faceEngine.detectFaces(imageInfo2.getImageData(), imageInfo2.getWidth(), imageInfo2.getHeight(), imageInfo.getImageFormat(), faceInfoList2);
        //特征提取2
        FaceFeature faceFeature2 = new FaceFeature();
        errorCode = faceEngine.extractFaceFeature(imageInfo2.getImageData(), imageInfo2.getWidth(), imageInfo2.getHeight(), imageInfo.getImageFormat(), faceInfoList2.get(0), faceFeature2);
        map.put("2特征值大小", faceFeature.getFeatureData().length);
        //特征比对
        FaceFeature targetFaceFeature = new FaceFeature();
        targetFaceFeature.setFeatureData(faceFeature.getFeatureData());
        FaceFeature sourceFaceFeature = new FaceFeature();
        sourceFaceFeature.setFeatureData(faceFeature2.getFeatureData());
        FaceSimilar faceSimilar = new FaceSimilar();
        errorCode = faceEngine.compareFaceFeature(targetFaceFeature, sourceFaceFeature, faceSimilar);
        map.put("相似度", faceSimilar.getScore());
        //设置活体测试
        errorCode = faceEngine.setLivenessParam(0.5f, 0.7f);
        //人脸属性检测
        FunctionConfiguration configuration = new FunctionConfiguration();
        configuration.setSupportAge(true);
        configuration.setSupportFace3dAngle(true);
        configuration.setSupportGender(true);
        configuration.setSupportLiveness(true);
        errorCode = faceEngine.process(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList, configuration);
        //性别检测
        List<GenderInfo> genderInfoList = new ArrayList<>();
        //获取性别信息
        errorCode = faceEngine.getGender(genderInfoList);
        if (genderInfoList.size() > 0) {
            if (genderInfoList.get(0).getGender() == 1) {
                map.put("性别", "女");
            } else if (genderInfoList.get(0).getGender() == 0) {
                map.put("性别", "男");
            }
        } else {
            map.put("性别", "未识别");
        }
        List<AgeInfo> ageInfoList = new ArrayList<AgeInfo>();
        //获取年龄信息
        errorCode = faceEngine.getAge(ageInfoList);
        if (ageInfoList.size() > 0)
            map.put("年龄", ageInfoList.get(0).getAge());
        else
            map.put("年龄", "未知");
        //3D信息检测
        List<Face3DAngle> face3DAngleList = new ArrayList<Face3DAngle>();
        //获取人脸三维角度信息
        errorCode = faceEngine.getFace3DAngle(face3DAngleList);
        if (face3DAngleList.size() > 0)
            map.put("3D角度", face3DAngleList.get(0).getPitch() + "," + face3DAngleList.get(0).getRoll() + "," + face3DAngleList.get(0).getYaw());
        else
            map.put("3D角度", "未识别");
        //活体检测
        List<LivenessInfo> livenessInfoList = new ArrayList<LivenessInfo>();
        //获取新的RGB活体信息对象
        errorCode = faceEngine.getLiveness(livenessInfoList);
        if (livenessInfoList.size() > 0) {
            //未知=-1 、非活体=0 、活体=1、超出人脸=-2
            if (livenessInfoList.get(0).getLiveness() == -1) {
                map.put("RGB活体值", "未知");
            } else if (livenessInfoList.get(0).getLiveness() == 0) {
                map.put("RGB活体值", "非活体");
            } else if (livenessInfoList.get(0).getLiveness() == 1) {
                map.put("RGB活体值", "活体");
            } else if (livenessInfoList.get(0).getLiveness() == -2) {
                map.put("RGB活体值", "超出人脸");
            }
        } else {
            map.put("RGB活体值", "未识别");
        }
        //IR属性处理
        ImageInfo imageInfoGray = getGrayData(new File(irt));
        List<FaceInfo> faceInfoListGray = new ArrayList<FaceInfo>();
        //人脸检测
        errorCode = faceEngine.detectFaces(imageInfoGray.getImageData(), imageInfoGray.getWidth(), imageInfoGray.getHeight(), imageInfoGray.getImageFormat(), faceInfoListGray);
        FunctionConfiguration configuration2 = new FunctionConfiguration();
        //设置是否支持IR活体检测
        configuration2.setSupportIRLiveness(true);
        /*
         RGB活体、年龄、性别、三维角度检测，在调用该函数后，可以调用getLiveness(List) ，getAge(List)，getGender(List)，getFace3DAngle(List)
         分别获取 RGB活体、年龄、性别、三维角度的检测结果；
         RGB活体最多支持 1 个人脸信息的检测，超过部分返回未知；
         年龄、性别、三维角度最多支持4个人脸信息的检测，超过部分返回未知
         */
        errorCode = faceEngine.processIr(imageInfoGray.getImageData(), imageInfoGray.getWidth(), imageInfoGray.getHeight(), imageInfoGray.getImageFormat(), faceInfoListGray, configuration2);
        //IR活体检测
        List<IrLivenessInfo> irLivenessInfo = new ArrayList<>();
        //获取新的IR活体信息对象
        errorCode = faceEngine.getLivenessIr(irLivenessInfo);
        if (irLivenessInfo.size() > 0) {
            //IR活体值，未知=-1 、非活体=0 、活体=1、超出人脸=-2
            if (irLivenessInfo.get(0).getLiveness() == -1) {
                map.put("IR活体值", "未知");
            } else if (irLivenessInfo.get(0).getLiveness() == 0) {
                map.put("IR活体值", "非活体");
            } else if (irLivenessInfo.get(0).getLiveness() == 1) {
                map.put("IR活体值", "活体");
            } else if (irLivenessInfo.get(0).getLiveness() == -2) {
                map.put("IR活体值", "超出人脸");
            }
        } else {
            map.put("IR活体值", "未识别");
        }
        ImageInfoEx imageInfoEx = new ImageInfoEx();
        imageInfoEx.setHeight(imageInfo.getHeight());
        imageInfoEx.setWidth(imageInfo.getWidth());
        imageInfoEx.setImageFormat(imageInfo.getImageFormat());
        imageInfoEx.setImageDataPlanes(new byte[][]{imageInfo.getImageData()});
        imageInfoEx.setImageStrides(new int[]{imageInfo.getWidth() * 3});
        List<FaceInfo> faceInfoList1 = new ArrayList<>();
        //图像信息
        errorCode = faceEngine.detectFaces(imageInfoEx, DetectModel.ASF_DETECT_MODEL_RGB, faceInfoList1);
        FunctionConfiguration fun = new FunctionConfiguration();
        //设置是否支持年龄检测
        fun.setSupportAge(true);
        errorCode = faceEngine.process(imageInfoEx, faceInfoList1, functionConfiguration);
        List<AgeInfo> ageInfoList1 = new ArrayList<>();
        //获取年龄信息
        faceEngine.getAge(ageInfoList1);
        if (ageInfoList1.size() > 0)
            map.put("IR图年龄", ageInfoList1.get(0).getAge());
        else
            map.put("IR图年龄", "未识别");
        FaceFeature feature = new FaceFeature();
        if (faceInfoList1.size() > 0)
            errorCode = faceEngine.extractFaceFeature(imageInfoEx, faceInfoList1.get(0), feature);
        map.put("错误码", errorCode);
        return map;
    }

    public static int unInit() {
        //引擎卸载
        return faceEngine.unInit();
    }
}
